/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package checkers.web;

import checkers.businessLogic.UIDGenerator;
import checkers.businessLogic.game.Position;
import checkers.constants.freemarker.Tags;
import checkers.constants.messages.DatabaseMessages;
import checkers.constants.web.FormParameters;
import checkers.constants.web.SessionAttributes;
import checkers.constants.web.WebPages;
import checkers.constants.web.requests.Pages;
import checkers.constants.web.requests.Parameters;
import checkers.exceptions.RequestNotAllowedException;
import freemarker.template.Configuration;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Calendar;
import java.sql.Date;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;

/**
 *
 * @author artinshahverdian
 */
//@WebServlet(name = "ControllerServlet", urlPatterns = {"/Checkers"})
public class RequestDispatcher extends HttpServlet {

    private Configuration configuration;
    private UserOperationsViewGenerator userOperationsViewGenerator;
    private GameOperationsViewGenerator gameOperationsViewGenerator;
    private final String NAME = "/Checkers";
    private final String CONTEXT = "/Checkers";
    private final int PATH_INITIAL_SIZE = NAME.length() + CONTEXT.length();

    @Override
    public void init() {
        configuration = new Configuration();    // FreeMarker Configuration Class

        configuration.setServletContextForTemplateLoading(getServletContext(), "");
        try {
            userOperationsViewGenerator = new UserOperationsViewGenerator(configuration);
        }
        catch (Exception ex) {
            Logger.getLogger(RequestDispatcher.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            gameOperationsViewGenerator = new GameOperationsViewGenerator(configuration);
        }
        catch (Exception ex) {
            Logger.getLogger(RequestDispatcher.class.getName()).log(Level.SEVERE, null, ex);
        }


    }

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        String uri = request.getRequestURI();

        //String contextPath = request.getContextPath();

        String page = uri.substring(PATH_INITIAL_SIZE + 1);
        String parameter = request.getParameter(Parameters.OPERATION_PARAMETER);

        try {

            if (page.equals("")) {
                //userOperationsViewGenerator.forwardHome(request, false).generateView(out);

                response.sendRedirect(Pages.HOME);
            }
            else if (page.equals(Pages.HOME)) {

                String err = request.getParameter(Parameters.ERROR);

                if (err != null) {
                    userOperationsViewGenerator.forwardHome(request, true).generateView(out);
                }
                else if (parameter == null) {

                    View view = userOperationsViewGenerator.forwardHome(request, false);

                    view.generateView(out);

                }
                else if (parameter.equals(Parameters.UPDATE_TABLE)) {

                    String gameTables = gameOperationsViewGenerator.getGameTablesJsonObject();
                    out.println(gameTables);

                }
                else if (parameter.equals(Parameters.CREATE_GAME_TABLE)) {


                    String userId = (String) request.getSession(false).getAttribute(SessionAttributes.USER_ID);
                    String gameTableName = request.getParameter(FormParameters.GAME_TABLE_NAME);
                    boolean success = gameOperationsViewGenerator.createGameTable(request, userId, gameTableName);
//                    view.generateView(out);
                    if (!success) {
                        response.sendRedirect(Pages.HOME + "?" + Parameters.ERROR + "=1");
                    }
                    else {
                        response.sendRedirect(Pages.HOME);
                    }


                }
                else if (parameter.equals(Parameters.JOIN_TABLE)) {
                    HttpSession session = request.getSession();
                    String userId = (String) session.getAttribute(SessionAttributes.USER_ID);
                    if (userId == null) {
                        userId = SessionAttributes.GUEST_ID + UIDGenerator.GenerateID();
                        session.setAttribute(SessionAttributes.USER_ID, userId);
                    }
                    String gameTableName = request.getParameter(Parameters.GAME_TABLE_NAME);


                    boolean success = gameOperationsViewGenerator.joinTable(userId, gameTableName, request);

                    if (success) {
                        response.sendRedirect(Pages.GAME + "?" + Parameters.GAME_TABLE_NAME + "=" + gameTableName);
                    }
                    else {
                        response.sendRedirect(Pages.HOME);
                    }



                }
                else if (parameter.equals(Parameters.LOGOUT)) {
                    userOperationsViewGenerator.logout(request);
                    response.sendRedirect(Pages.HOME);
                }
                else if (parameter.equals(Parameters.GET_GAME_TABLE)) {
                    HttpSession session = request.getSession();
                    String tableName = (String) session.getAttribute(SessionAttributes.GAME_TABLE_NAME);
                    if (tableName == null) {
                        out.println("");
                    }
                    else {
                        String game = gameOperationsViewGenerator.getGameTableJSON(tableName);
                        out.println(game);
                    }
                }
                else if (parameter.equals(Parameters.LOAD_GAME)) {
                    HttpSession session = request.getSession();
                    String gameTableName = (String) session.getAttribute(SessionAttributes.GAME_TABLE_NAME);
                    if (gameTableName != null) {
                        out.println(Pages.GAME + "?" + Parameters.GAME_TABLE_NAME + "=" + gameTableName);
                    }
                }
                else if (parameter.equals(Parameters.GET_HIGH_RANKINGS)) {
                    String highRankingUsersJSON = userOperationsViewGenerator.getHighRankingsJSON();
                    out.println(highRankingUsersJSON);
                }
            }
            else if (page.equals(Pages.GAME)) {
                String gameTableName = request.getParameter(Parameters.GAME_TABLE_NAME);

                if (parameter != null) {
                    if (parameter.equals(Parameters.UPDATE_GAME)) {

                        String gameJson = gameOperationsViewGenerator.getGameTableJSON(gameTableName);

                        out.println(gameJson);
                    }
                    else if (parameter.endsWith(Parameters.MAKE_MOVE)) {
                        String paramFrom = request.getParameter(Parameters.MAKE_MOVE_FROM);
                        String paramTo = request.getParameter(Parameters.MAKE_MOVE_TO);
                        int f = Integer.parseInt(paramFrom);
                        int t = Integer.parseInt(paramTo);
                        gameTableName = request.getParameter(Parameters.GAME_TABLE_NAME);

                        int fromx = f / 10;
                        int fromy = f % 10;
                        Position from = new Position(f / 10, f % 10);
                        Position to = new Position(t / 10, t % 10);

                        String gameJson;
                        gameJson = gameOperationsViewGenerator.makeMove(from, to, gameTableName);

                        out.println(gameJson);

                    }
                    else if (parameter.equals(Parameters.DELETE_TABLE)) {
                        gameTableName = request.getParameter(Parameters.GAME_TABLE_NAME);
                        gameOperationsViewGenerator.deleteTable(gameTableName);
                    }
                    else if (parameter.equals(Parameters.GET_REMAINING_TIME)) {
                        long res = gameOperationsViewGenerator.getRemainingTime(gameTableName);
                        out.print(res);

                    }
                }
                else if (gameTableName != null) {
                    try {
                        gameOperationsViewGenerator.getGameTable(gameTableName, request).generateView(out);
                    }
                    catch (RequestNotAllowedException ex) {
                        Logger.getLogger(RequestDispatcher.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

            }
            else if (page.equals(Pages.REGISTER)) {


                String err = request.getParameter(Parameters.ERROR);

                if (err != null) {
                }

                if (parameter == null) {
                    //userOperationsViewGenerator.forwardRegister(request).generateView(out);

                    boolean error = false;
                    if (err != null) {
                        error = true;
                    }
                    View view = userOperationsViewGenerator.forwardRegister(request);

                    view.generateView(out);

                }
                else if (parameter.equals(Parameters.REGISTER)) {
                    String email = request.getParameter(FormParameters.EMAIL);
                    String password = request.getParameter(FormParameters.PASSWORD);
                    String firstName = request.getParameter(FormParameters.FIRST_NAME);
                    String lastName = request.getParameter(FormParameters.LAST_NAME);
                    String securityQuestion = request.getParameter(FormParameters.SECURITY_QUESTION);
                    String securityAnswer = request.getParameter(FormParameters.SECURITY_ANSWER);
                    int birthMonth = Integer.parseInt(request.getParameter(FormParameters.BIRTH_MONTH));
                    int birthDay = Integer.parseInt(request.getParameter(FormParameters.BIRTH_DAY));
                    int birthYear = Integer.parseInt(request.getParameter(FormParameters.BIRTH_YEAR));
                    Calendar calendar = Calendar.getInstance();
                    calendar.set(birthYear, birthMonth - 1, birthDay);

                    Date birthDate = new Date(calendar.getTimeInMillis());

                    View view = userOperationsViewGenerator.register(email, password,
                            firstName, lastName, birthDate, securityQuestion, securityAnswer);


                    view.generateView(out);
                }



            }
            else if (page.equals(Pages.LOGIN)) {

                String err = request.getParameter(Parameters.ERROR);

                if (err != null) {
                    userOperationsViewGenerator.forwardLogin(request, true).generateView(out);
                }
                else if (parameter == null) {
                    userOperationsViewGenerator.forwardLogin(request, false).generateView(out);
                }
                else if (parameter.equals(Parameters.LOGIN)) {

                    String email, password;
                    email = request.getParameter(FormParameters.EMAIL);
                    password = request.getParameter(FormParameters.PASSWORD);
//                    userOperationsViewGenerator.Login(email, password, request, response);

                    boolean success = userOperationsViewGenerator.login(email, password, request);

                    if (!success) {
                        response.sendRedirect(Pages.LOGIN + "?" + Parameters.ERROR + "=1");

                    }
                    else {
                        response.sendRedirect(Pages.HOME);
                    }

                }


            }
            else if (page.equals(Pages.FORGOT_PASSWORD)) {
                if (parameter == null) {
                    View view = userOperationsViewGenerator.forwardForgotPassword();

                    view.generateView(out);

                }
                else if (parameter.equals(Parameters.GET_SECURITY_QUESTION)) {
                    String email = request.getParameter(FormParameters.EMAIL);
                    View view = userOperationsViewGenerator.getSecurityQuestion(email);
                    view.generateView(out);
                }
                else if (parameter.equals(Parameters.RECOVER_PASSWORD)) {

                    String email = request.getParameter(FormParameters.EMAIL);
                    String securityAnswer = request.getParameter(FormParameters.SECURITY_ANSWER);

                    View view = userOperationsViewGenerator.recoverPassword(email, securityAnswer);

                    view.generateView(out);

                }



            }
            else if (page.equals(Pages.EDIT_PROFILE)) {


                String err = request.getParameter(Parameters.ERROR);

                if (err != null) {
                    userOperationsViewGenerator.forwardEditProfile(request, true);
                }

                if (parameter == null) {
                    //userOperationsViewGenerator.forwardRegister(request).generateView(out);

                    boolean error = false;
                    if (err != null) {
                        error = true;
                    }
                    View view = userOperationsViewGenerator.forwardEditProfile(request, false);

                    view.generateView(out);

                }
                else if (parameter.equals(Parameters.EDIT_PROFILE)) {
                    String email = request.getParameter(FormParameters.EMAIL);
                    String password = request.getParameter(FormParameters.PASSWORD);
                    String firstName = request.getParameter(FormParameters.FIRST_NAME);
                    String lastName = request.getParameter(FormParameters.LAST_NAME);
                    String securityQuestion = request.getParameter(FormParameters.SECURITY_QUESTION);
                    String securityAnswer = request.getParameter(FormParameters.SECURITY_ANSWER);
                    int birthMonth = Integer.parseInt(request.getParameter(FormParameters.BIRTH_MONTH));
                    int birthDay = Integer.parseInt(request.getParameter(FormParameters.BIRTH_DAY));
                    int birthYear = Integer.parseInt(request.getParameter(FormParameters.BIRTH_YEAR));
                    Calendar calendar = Calendar.getInstance();
                    calendar.set(birthYear, birthMonth - 1, birthDay);

                    Date birthDate = new Date(calendar.getTimeInMillis());

                    View view = userOperationsViewGenerator.editProfile(email, password,
                            firstName, lastName, birthDate, securityQuestion, securityAnswer, request);


                    view.generateView(out);
                }
                else if (parameter.equals(Parameters.GET_USER_INFORMATION)) {

                    String userInformation = userOperationsViewGenerator.getUserInformation(request);
                    out.print(userInformation);
                }



            }

        }
        catch (SQLException ex) {
            Logger.getLogger(UserOperationsViewGenerator.class.getName()).log(Level.SEVERE, null, ex);

            Map map = new HashMap();
            map.put(Tags.EXTERNAL_ERROR, DatabaseMessages.DATABASE_ERROR);
            new View(map, WebPages.EXTERNAL_ERRORS, configuration).generateView(out);
        }
        catch (Exception ex) {
            Logger.getLogger(RequestDispatcher.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally {
            out.close();
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {


        System.out.println("doGet");
        processRequest(request, response);


    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);


    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
